Merge "Fixing definition and use of $attrs parameter in Html::buttonAttributes"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 2 Jun 2015 14:20:07 +0000 (14:20 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 2 Jun 2015 14:20:07 +0000 (14:20 +0000)
composer.json
docs/extension.schema.json
includes/api/i18n/en.json
includes/db/LoadBalancer.php
includes/mail/UserMailer.php
includes/page/WikiPage.php
languages/Language.php
resources/src/mediawiki.ui/components/checkbox.less
tests/phpunit/languages/LanguageTest.php

index 8210236..9222aa4 100644 (file)
@@ -32,7 +32,7 @@
        "require-dev": {
                "jakub-onderka/php-parallel-lint": "~0.8",
                "justinrainbow/json-schema": "~1.3",
-               "phpunit/phpunit": "~4.5",
+               "phpunit/phpunit": "3.7.37",
                "mediawiki/mediawiki-codesniffer": "0.1.0"
        },
        "suggest": {
index 05f0c45..c4c716b 100644 (file)
@@ -30,8 +30,7 @@
                        "description": "Extension's authors.",
                        "items": {
                                "type": "string"
-                       },
-                       "additionalItems": false
+                       }
                },
                "version": {
                        "type": "string",
index d905dea..f3faf48 100644 (file)
@@ -10,8 +10,8 @@
        "apihelp-main-param-action": "Which action to perform.",
        "apihelp-main-param-format": "The format of the output.",
        "apihelp-main-param-maxlag": "Maximum lag can be used when MediaWiki is installed on a database replicated cluster. To save actions causing any more site replication lag, this parameter can make the client wait until the replication lag is less than the specified value. In case of excessive lag, error code <samp>maxlag</samp> is returned with a message like <samp>Waiting for $host: $lag seconds lagged</samp>.<br />See [[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]] for more information.",
-       "apihelp-main-param-smaxage": "Set the <code>s-maxage</code> header to this many seconds. Errors are never cached.",
-       "apihelp-main-param-maxage": "Set the <code>max-age</code> header to this many seconds. Errors are never cached.",
+       "apihelp-main-param-smaxage": "Set the <code>s-maxage</code> HTTP cache control header to this many seconds. Errors are never cached.",
+       "apihelp-main-param-maxage": "Set the <code>max-age</code> HTTP cache control header to this many seconds. Errors are never cached.",
        "apihelp-main-param-assert": "Verify the user is logged in if set to <kbd>user</kbd>, or has the bot userright if <kbd>bot</kbd>.",
        "apihelp-main-param-requestid": "Any value given here will be included in the response. May be used to distinguish requests.",
        "apihelp-main-param-servedby": "Include the hostname that served the request in the results.",
index 2ea2487..99c9a14 100644 (file)
@@ -291,8 +291,8 @@ class LoadBalancer {
                                return false;
                        }
 
-                       wfDebugLog( 'connect', __METHOD__ .
-                               ": Using reader #$i: {$this->mServers[$i]['host']}..." );
+                       $serverName = $this->getServerName( $i );
+                       wfDebugLog( 'connect', __METHOD__ . ": Using reader #$i: $serverName..." );
 
                        $conn = $this->openConnection( $i, $wiki );
                        if ( !$conn ) {
@@ -462,7 +462,7 @@ class LoadBalancer {
 
                if ( $result == -1 || is_null( $result ) ) {
                        # Timed out waiting for slave, use master instead
-                       $server = $this->mServers[$index]['host'];
+                       $server = $server = $this->getServerName( $index );
                        $msg = __METHOD__ . ": Timed out waiting on $server pos {$this->mWaitForPos}";
                        wfDebug( "$msg\n" );
                        wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
@@ -660,11 +660,12 @@ class LoadBalancer {
                        $server = $this->mServers[$i];
                        $server['serverIndex'] = $i;
                        $conn = $this->reallyOpenConnection( $server, false );
+                       $serverName = $this->getServerName( $i );
                        if ( $conn->isOpen() ) {
-                               wfDebug( "Connected to database $i at {$this->mServers[$i]['host']}\n" );
+                               wfDebug( "Connected to database $i at $serverName\n" );
                                $this->mConns['local'][$i][0] = $conn;
                        } else {
-                               wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
+                               wfDebug( "Failed to connect to database $i at $serverName\n" );
                                $this->mErrorConnection = $conn;
                                $conn = false;
                        }
@@ -888,12 +889,14 @@ class LoadBalancer {
         */
        public function getServerName( $i ) {
                if ( isset( $this->mServers[$i]['hostName'] ) ) {
-                       return $this->mServers[$i]['hostName'];
+                       $name = $this->mServers[$i]['hostName'];
                } elseif ( isset( $this->mServers[$i]['host'] ) ) {
-                       return $this->mServers[$i]['host'];
+                       $name = $this->mServers[$i]['host'];
                } else {
-                       return '';
+                       $name = '';
                }
+
+               return ( $name != '' ) ? $name : 'localhost';
        }
 
        /**
index 3cabdae..8264673 100644 (file)
@@ -206,6 +206,8 @@ class UserMailer {
                $headers['Date'] = MWTimestamp::getLocalInstance()->format( 'r' );
                $headers['Message-ID'] = self::makeMsgId();
                $headers['X-Mailer'] = 'MediaWiki mailer';
+               $headers['List-Unsubscribe'] = '<' . SpecialPage::getTitleFor( 'Preferences' )
+                       ->getFullURL( '', false, PROTO_CANONICAL ) . '>';
 
                # Line endings need to be different on Unix and Windows due to
                # the bug described at http://trac.wordpress.org/ticket/2603
index 8e2e8a5..1fd22cf 100644 (file)
@@ -2769,9 +2769,16 @@ class WikiPage implements Page, IDBAccessObject {
                $dbw->begin( __METHOD__ );
 
                if ( $id == 0 ) {
-                       $this->loadPageData( 'forupdate' );
+                       // T98706: lock the page from various other updates but avoid using
+                       // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to
+                       // the revisions queries (which also JOIN on user). Only lock the page
+                       // row and CAS check on page_latest to see if the trx snapshot matches.
+                       $latest = $this->lock();
+
+                       $this->loadPageData( WikiPage::READ_LATEST );
                        $id = $this->getID();
-                       if ( $id == 0 ) {
+                       if ( $id == 0 || $this->getLatest() != $latest ) {
+                               // Page not there or trx snapshot is stale
                                $dbw->rollback( __METHOD__ );
                                $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
                                return $status;
@@ -2878,6 +2885,24 @@ class WikiPage implements Page, IDBAccessObject {
                return $status;
        }
 
+       /**
+        * Lock the page row for this title and return page_latest (or 0)
+        *
+        * @return integer
+        */
+       protected function lock() {
+               return (int)wfGetDB( DB_MASTER )->selectField(
+                       'page',
+                       'page_latest',
+                       array(
+                               'page_namespace' => $this->getTitle()->getNamespace(),
+                               'page_title' => $this->getTitle()->getDBkey()
+                       ),
+                       __METHOD__,
+                       array( 'FOR UPDATE' )
+               );
+       }
+
        /**
         * Do some database updates after deletion
         *
index 18f4594..d19dc25 100644 (file)
@@ -2034,7 +2034,18 @@ class Language {
                static $table = array(
                        array( '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' ),
                        array( '', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק' ),
-                       array( '', 'ק', 'ר', 'ש', 'ת', 'תק', 'תר', 'תש', 'תת', 'תתק', 'תתר' ),
+                       array( '',
+                               array( 'ק' ),
+                               array( 'ר' ),
+                               array( 'ש' ),
+                               array( 'ת' ),
+                               array( 'ת', 'ק' ),
+                               array( 'ת', 'ר' ),
+                               array( 'ת', 'ש' ),
+                               array( 'ת', 'ת' ),
+                               array( 'ת', 'ת', 'ק' ),
+                               array( 'ת', 'ת', 'ר' ),
+                       ),
                        array( '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' )
                );
 
@@ -2043,47 +2054,59 @@ class Language {
                        return $num;
                }
 
-               $s = '';
+               // Round thousands have special notations
+               if ( $num === 1000 ) {
+                       return "א' אלף";
+               } elseif ( $num % 1000 === 0 ) {
+                       return $table[0][$num / 1000] . "' אלפים";
+               }
+
+               $letters = array();
+
                for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
                        if ( $num >= $pow10 ) {
-                               if ( $num == 15 || $num == 16 ) {
-                                       $s .= $table[0][9] . $table[0][$num - 9];
+                               if ( $num === 15 || $num === 16 ) {
+                                       $letters[] = $table[0][9];
+                                       $letters[] = $table[0][$num - 9];
                                        $num = 0;
                                } else {
-                                       $s .= $table[$i][intval( ( $num / $pow10 ) )];
-                                       if ( $pow10 == 1000 ) {
-                                               $s .= "'";
+                                       $letters = array_merge(
+                                               $letters,
+                                               (array)$table[$i][intval( $num / $pow10 )]
+                                       );
+
+                                       if ( $pow10 === 1000 ) {
+                                               $letters[] = "'";
                                        }
                                }
                        }
+
                        $num = $num % $pow10;
                }
-               if ( strlen( $s ) == 2 ) {
-                       $str = $s . "'";
+
+               $preTransformLength = count( $letters );
+               if ( $preTransformLength === 1 ) {
+                       // Add geresh (single quote) to one-letter numbers
+                       $letters[] = "'";
                } else {
-                       $str = substr( $s, 0, strlen( $s ) - 2 ) . '"';
-                       $str .= substr( $s, strlen( $s ) - 2, 2 );
-               }
-               $start = substr( $str, 0, strlen( $str ) - 2 );
-               $end = substr( $str, strlen( $str ) - 2 );
-               switch ( $end ) {
-                       case 'כ':
-                               $str = $start . 'ך';
-                               break;
-                       case 'מ':
-                               $str = $start . 'ם';
-                               break;
-                       case 'נ':
-                               $str = $start . 'ן';
-                               break;
-                       case 'פ':
-                               $str = $start . 'ף';
-                               break;
-                       case 'צ':
-                               $str = $start . 'ץ';
-                               break;
+                       $lastIndex = $preTransformLength - 1;
+                       $letters[$lastIndex] = str_replace(
+                               array( 'כ', 'מ', 'נ', 'פ', 'צ' ),
+                               array( 'ך', 'ם', 'ן', 'ף', 'ץ' ),
+                               $letters[$lastIndex]
+                       );
+
+                       // Add gershayim (double quote) to multiple-letter numbers,
+                       // but exclude numbers with only one letter after the thousands
+                       // (1001-1009, 1020, 1030, 2001-2009, etc.)
+                       if ( $letters[1] === "'" && $preTransformLength === 3 ) {
+                               $letters[] = "'";
+                       } else {
+                               array_splice( $letters, -1, 0, '"' );
+                       }
                }
-               return $str;
+
+               return implode( $letters );
        }
 
        /**
index 4829f5f..ac5becb 100644 (file)
@@ -54,6 +54,9 @@
                // we hide the input element as instead we will style the label that follows
                // we use opacity so that VoiceOver software can still identify it
                opacity: 0;
+               // Render "on top of" the label, so that it's still clickable (T98905)
+               z-index: 1;
+               position: relative;
                // ensure the invisible checkbox takes up the required width
                width: @checkboxSize;
                height: @checkboxSize;
index cff2e8f..faa30c3 100644 (file)
@@ -1412,6 +1412,77 @@ class LanguageTest extends LanguageClassesTestCase {
                );
        }
 
+       /**
+        * @dataProvider provideHebrewNumeralsData
+        * @covers Language::hebrewNumeral
+        */
+       public function testHebrewNumeral( $num, $numerals ) {
+               $this->assertEquals(
+                       $numerals,
+                       Language::hebrewNumeral( $num ),
+                       "hebrewNumeral('$num')"
+               );
+       }
+
+       public static function provideHebrewNumeralsData() {
+               return array(
+                       array( -1, -1 ),
+                       array( 0, 0 ),
+                       array( 1, "א'" ),
+                       array( 2, "ב'" ),
+                       array( 3, "ג'" ),
+                       array( 4, "ד'" ),
+                       array( 5, "ה'" ),
+                       array( 6, "ו'" ),
+                       array( 7, "ז'" ),
+                       array( 8, "ח'" ),
+                       array( 9, "ט'" ),
+                       array( 10, "י'" ),
+                       array( 11, 'י"א' ),
+                       array( 14, 'י"ד' ),
+                       array( 15, 'ט"ו' ),
+                       array( 16, 'ט"ז' ),
+                       array( 17, 'י"ז' ),
+                       array( 20, "כ'" ),
+                       array( 21, 'כ"א' ),
+                       array( 30, "ל'" ),
+                       array( 40, "מ'" ),
+                       array( 50, "נ'" ),
+                       array( 60, "ס'" ),
+                       array( 70, "ע'" ),
+                       array( 80, "פ'" ),
+                       array( 90, "צ'" ),
+                       array( 99, 'צ"ט' ),
+                       array( 100, "ק'" ),
+                       array( 101, 'ק"א' ),
+                       array( 110, 'ק"י' ),
+                       array( 200, "ר'" ),
+                       array( 300, "ש'" ),
+                       array( 400, "ת'" ),
+                       array( 500, 'ת"ק' ),
+                       array( 800, 'ת"ת' ),
+                       array( 1000, "א' אלף" ),
+                       array( 1001, "א'א'" ),
+                       array( 1012, "א'י\"ב" ),
+                       array( 1020, "א'ך'" ),
+                       array( 1030, "א'ל'" ),
+                       array( 1081, "א'פ\"א" ),
+                       array( 2000, "ב' אלפים" ),
+                       array( 2016, "ב'ט\"ז" ),
+                       array( 3000, "ג' אלפים" ),
+                       array( 4000, "ד' אלפים" ),
+                       array( 4904, "ד'תתק\"ד" ),
+                       array( 5000, "ה' אלפים" ),
+                       array( 5680, "ה'תר\"ף" ),
+                       array( 5690, "ה'תר\"ץ" ),
+                       array( 5708, "ה'תש\"ח" ),
+                       array( 5720, "ה'תש\"ך" ),
+                       array( 5740, "ה'תש\"ם" ),
+                       array( 5750, "ה'תש\"ן" ),
+                       array( 5775, "ה'תשע\"ה" ),
+               );
+       }
+
        /**
         * @dataProvider providePluralData
         * @covers Language::convertPlural